package com.zxpic.web;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import com.sleepycat.je.Cursor;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.EnvironmentLockedException;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;

public class BerkeleyDBUtils {
	private static final String DEFAULT_ENCODING = "utf-8";
	// private static final int CACHE_PERCENT = 65;
	private int CACHE_SIZE = 1024 * 1024 * 4;
	private String dbPath = "d:/berkekeyDb";

	private Environment myDbEnvironment = null;
	private Database myDatabase = null;
	// private Cursor myCursor = null;
	private EnvironmentConfig envConfig = null;
	public String databaseName = "sampleDatabase";
	public DatabaseConfig dbConfig;

	public static void main(String[] args) throws IOException, DatabaseException {
		BerkeleyDBUtils s = new BerkeleyDBUtils("~/test/");
		// s.putString("joey", "huzhiyongddddddddddddddddddd");
		for (int i = 0; i < 100; i++) {
			s.putString(i + "", i + "");
		}

		for (Object[] objs : s.getDatas(2, 8)) {
			System.out.println(new String((byte[]) objs[1]));
		}

	}

	public BerkeleyDBUtils(String path) {
		File file = new File(path);
		if (!file.exists()) {
			file.mkdirs();
		}
		String dbPath2 = path == null ? dbPath : path;
		System.out.println("bdbPath:" + dbPath2);
		this.setDbPath(dbPath2);
		try {
			this.setup();
		} catch (EnvironmentLockedException e) {
			e.printStackTrace();
		} catch (DatabaseException e) {
			e.printStackTrace();
		}
	}

	public void cleanAllData() throws DatabaseException {
		getMyDatabase().close();
		getMyDbEnvironment().removeDatabase(null, databaseName);
		setMyDatabase(getMyDbEnvironment().openDatabase(null, databaseName, dbConfig));
	}

	public List<Object[]> getDatas(long start, long size) throws DatabaseException, IOException {
		DatabaseEntry key = new DatabaseEntry();
		DatabaseEntry data = new DatabaseEntry();
		List<Object[]> li = new ArrayList<Object[]>();
		Cursor m = this.getMyDatabase().openCursor(null, null);
		long maxNo = start + size;
		if (m.getDatabase().count() < start || start < 0 || size <= 0) {
			return li;
		}
		long index = 0;

		while ((index++ < maxNo) && m.getNext(key, data, null) == OperationStatus.SUCCESS) {
			if (index <= start)
				continue;
			byte[] content = data.getData();

			li.add(new Object[] { key.getData(), content });
		}
		m.close();
		return li;
	}

	private void setup() throws EnvironmentLockedException, DatabaseException {
		setEnvConfig(new EnvironmentConfig());
		getEnvConfig().setAllowCreate(true);
		// envConfig.setCachePercent(CACHE_PERCENT);
		getEnvConfig().setCacheSize(CACHE_SIZE);
		getEnvConfig().setConfigParam(EnvironmentConfig.LOG_FILE_MAX, String.valueOf(1024 * 1024 * 64));
		setMyDbEnvironment(new Environment(new File(getDbPath()), getEnvConfig()));

		dbConfig = new DatabaseConfig();
		dbConfig.setAllowCreate(true);
		// 延迟写数据，减少io
		dbConfig.setDeferredWrite(true);
		// transaction为null，不支持事务

		setMyDatabase(getMyDbEnvironment().openDatabase(null, databaseName, dbConfig));
		// this.myCursor = this.getMyDatabase().openCursor(null, null);
	}

	public void putString(String key, String value, String defaultEncoding) {
		try {
			String charsetName = defaultEncoding == null ? DEFAULT_ENCODING : defaultEncoding;
			byte[] bytes = key.getBytes(charsetName);
			byte[] bytes2 = value.getBytes(charsetName);
			putByte(bytes, bytes2);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void deleteString(String key, String defaultEncoding) {
		try {
			String charsetName = defaultEncoding == null ? DEFAULT_ENCODING : defaultEncoding;
			byte[] bytes = key.getBytes(charsetName);
			deleteByte(bytes);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void putByte(byte[] bytesKey, byte[] bytesValue) throws DatabaseException, IOException {
		DatabaseEntry theKey = new DatabaseEntry(bytesKey);
		DatabaseEntry theValue = new DatabaseEntry(bytesValue);
		myDatabase.put(null, theKey, theValue);
	}

	public void deleteByte(byte[] bytesKey) throws DatabaseException {
		DatabaseEntry theKey = new DatabaseEntry(bytesKey);
		myDatabase.delete(null, theKey);
	}

	public String getString(String key, String defaultEncoding) {
		String foundData = null;
		try {
			String charsetName = defaultEncoding == null ? DEFAULT_ENCODING : defaultEncoding;
			byte[] bytes = key.getBytes(charsetName);
			byte[] byter = getByte(bytes);
			if (byter != null)
				foundData = new String(byter, charsetName);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return foundData;
	}

	public void putInputStream(String string, InputStream inputStream) {
		try {
			byte[] bytes = new byte[1024 * 16];
			ByteArrayOutputStream by = new ByteArrayOutputStream();
			while (inputStream.read(bytes) != -1) {
				by.write(bytes);
			}
			putByte(string.getBytes(), by.toByteArray());
		} catch (DatabaseException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public byte[] getByte(byte[] bytesKey) throws DatabaseException, IOException {
		byte[] bytesValue = null;
		DatabaseEntry theKey = new DatabaseEntry(bytesKey);
		DatabaseEntry theData = new DatabaseEntry();
		if (myDatabase.get(null, theKey, theData, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
			bytesValue = theData.getData();
		}
		return bytesValue;
	}

	public void close() {
		try {

			if (getMyDatabase() != null) {
				getMyDatabase().close();
			}
			if (getMyDbEnvironment() != null) {
				getMyDbEnvironment().sync();
				getMyDbEnvironment().cleanLog();
				getMyDbEnvironment().close();
			}
		} catch (Exception dbe) {
			dbe.printStackTrace();
		}
	}

	public void setMyDatabase(Database myDatabase) {
		this.myDatabase = myDatabase;
	}

	public Database getMyDatabase() {
		return myDatabase;
	}

	public void setMyDbEnvironment(Environment myDbEnvironment) {
		this.myDbEnvironment = myDbEnvironment;
	}

	public Environment getMyDbEnvironment() {
		return myDbEnvironment;
	}

	public void putString(String key, String value) {
		putString(key, value, null);

	}

	public String getString(String key) {
		return getString(key, null);
	}

	public void setDbPath(String dbPath) {
		this.dbPath = dbPath;
	}

	public String getDbPath() {
		return dbPath;
	}

	public void setEnvConfig(EnvironmentConfig envConfig) {
		this.envConfig = envConfig;
	}

	public EnvironmentConfig getEnvConfig() {
		return envConfig;
	}

}
